package com.liuc.practice.server;

import com.liuc.practice.server.servlet.HttpServlet;
import com.liuc.practice.server.servlet.Servlet;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Wrapper;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author Liu Chang
 * @Date 2021/7/30 12:08 下午
 */
public class Mapper {

    public Mapper() {
        Map<String, Map<String, HttpServlet>> context = new HashMap<>();
        // 对于 minicat 来说，只有一个 context 集合
        this.setContext(context);
    }

    private String host;
    private String port;
    // 一个 Context 对应一个 web 应用，可以包含多个 wrapper，所以嵌套 Map
    // 一个 wrapper 对应 servlet，每个 servlet 都有一个对一个的 url-pattern
    private Map<String, Map<String, HttpServlet>> context;


    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public String getPort() {
        return port;
    }

    public void setPort(String port) {
        this.port = port;
    }

    public Map<String, Map<String, HttpServlet>> getContext() {
        return context;
    }

    public void setContext(Map<String, Map<String, HttpServlet>> context) {
        this.context = context;
    }

    /**
     * 解析 minicat 中的 server.xml
     * @throws Exception
     */
    public void parseServerXML() throws Exception {

        InputStream resourceAsStream = Bootstrap.class.getClassLoader().getResourceAsStream("server.xml");

        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(resourceAsStream);
        Element rootElement = document.getRootElement();
        List<Element> connectors = rootElement.selectNodes("//Connector");
        Element host = (Element) rootElement.selectNodes("//Host").get(0);
        this.setPort(connectors.get(0).attributeValue("port"));
        this.setHost(host.attributeValue("name"));
        String appBase = host.attributeValue("appBase");

        File applyFile = new File(appBase);
        for (File webapp : applyFile.listFiles()) {
            if (webapp.isDirectory() && webapp.listFiles().length > 0) {
                for (File file : webapp.listFiles()) {
                    if ("web.xml".equals(file.getName())) {
                        parseWebXML(appBase + "/" + webapp.getName(), this);
                    }
                }
            }
        }
    }

    /**
     * 解析 webapps 下的所有应用中的 web.xml
     * @param appPath
     *  @throws Exception
     */
    public void parseWebXML(String appPath, Mapper mapper) throws Exception {
        FileInputStream fis = new FileInputStream(appPath + "/web.xml");
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(fis);
        Element rootElement = document.getRootElement();
        List<Element> contexts = rootElement.selectNodes("//context");

        List<Element> servlets = rootElement.selectNodes("//servlet");
        for (Element element : servlets) {
            Map<String, HttpServlet> wrapper = new HashMap();
            Element servletNameElement = (Element) element.selectSingleNode("servlet-name");
            String servletNameValue = servletNameElement.getStringValue();

            Element servletClassElement = (Element) element.selectSingleNode("servlet-class");
            String servletClassValue = servletClassElement.getStringValue();

            // 根据 servletNameValue 找到对应的 servlet-mapping 中对应的 url-pattern
            Element servletMappingElement = (Element) (rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletNameValue + "']"));
            String urlPattern = servletMappingElement.selectSingleNode("url-pattern").getStringValue();
            // 加载应用内中的类
//            appPath + "/" + servletClassValue.replace(".","/")

            AppClassLoader appClassLoader = new AppClassLoader();
            Class servlet = appClassLoader.findClass(appPath + "/" + servletClassValue.replace(".","/") + ".class", servletClassValue);
            HttpServlet object = (HttpServlet)Class.forName(servlet.getName(), true, appClassLoader).newInstance();
            wrapper.put(urlPattern, object);
            mapper.getContext().put(contexts.get(0).getText(), wrapper);
        }
    }

}
